﻿#region - 版 本 注 释 -
/*----------------------------------------------------------------
 * 版权所有 (c) 2024   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-GLJ2Q8J
 * 公司名称：
 * 命名空间：AutoCAD.EntityTool
 * 唯一标识：76dbfa45-f50e-450f-9c06-cba357804ad7
 * 文件名：EditorTools
 * 当前用户域：DESKTOP-GLJ2Q8J
 * 
 * 创建者：Guo-79991
 * 电子邮箱：799919859@qq.com
 * 创建时间：2024/7/15 12:01:47
 * 版本：V1.0.0
 *
 * 功能描述(Description):
 * 参考文档(Reference):
 * 数据表(Tables):
 * 作者(Author):Guo
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion - 版 本 注 释 -



namespace AutoCAD.EntityTools
{
    /// <summary>
    /// EditorTools 的摘要说明
    /// </summary>
    public static class EditorTools
    {

        /// <summary>
        /// 将AutoCAD编辑器的视图缩放到指定的3D范围。
        /// </summary>
        /// <param name="ed">AutoCAD编辑器对象。</param>
        /// <param name="ext">要缩放的3D范围。</param>
        /// <exception cref="ArgumentNullException">当编辑器对象为null时抛出。</exception>
        /// <remarks>
        /// 此方法将根据提供的3D范围调整编辑器的视图，使得该范围完全显示在视图中。
        /// 它首先获取当前的视图记录，然后计算一个转换矩阵，将世界坐标转换为视图坐标。
        /// 接着，它使用这个矩阵来转换提供的范围，并更新视图记录的宽度和高度以及中心点。
        /// 最后，它将更新后的视图记录设置回编辑器，实现视图的缩放。
        /// </remarks>
        // 扩展Editor类以添加一个Zoom方法，该方法可以缩放到指定的3D范围
        public static void Zoom(this Editor ed, Extents3d ext)
        {
            // 检查编辑器对象是否为null，如果是，则抛出ArgumentNullException
            if (ed == null)
                throw new ArgumentNullException("ed");

            // 使用using语句确保在操作完成后释放资源
            using (ViewTableRecord view = ed.GetCurrentView())
            {
                // 构建一个世界到眼睛坐标系的转换矩阵
                Matrix3d worldToEye = Matrix3d.WorldToPlane(view.ViewDirection) *  // 将世界坐标转换到与视图方向平行的平面
                                      Matrix3d.Displacement(Point3d.Origin - view.Target) *  // 平移到视图的目标点
                                      Matrix3d.Rotation(view.ViewTwist, view.ViewDirection, view.Target);  // 旋转视图以匹配当前的扭曲角度

                // 使用转换矩阵变换指定的3D范围
                ext.TransformBy(worldToEye);

                // 计算新的视图宽度，即范围在X轴上的最大值与最小值之差
                view.Width = ext.MaxPoint.X - ext.MinPoint.X;
                // 计算新的视图高度，即范围在Y轴上的最大值与最小值之差
                view.Height = ext.MaxPoint.Y - ext.MinPoint.Y;

                // 设置视图的中心点为范围的最大和最小点的平均值
                view.CenterPoint = new Point2d(
                    (ext.MaxPoint.X + ext.MinPoint.X) / 2.0,  // X坐标的平均值
                    (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0); // Y坐标的平均值

                // 将更新后的视图记录设置回编辑器，以应用新的视图范围
                ed.SetCurrentView(view);
            }
        }


        /// <summary>
        /// 缩放到当前图形的范围
        /// </summary>
        /// <param name="ed">AutoCAD编辑器对象</param>
        public static void ZoomExtents(this Editor ed)
        {
            Database db = ed.Document.Database;
            db.UpdateExt(false);
            Extents3d ext = (short)Application.GetSystemVariable("cvport") == 1 ?
                new Extents3d(db.Pextmin, db.Pextmax) :
                new Extents3d(db.Extmin, db.Extmax);
            ed.Zoom(ext);
        }

        /// <summary>
        /// 获取CAD鼠标当前位置坐标
        /// </summary>
        /// <param name="ed">命令栏</param>
        /// <returns>坐标(可能为null)</returns>
        public static Point3d? GetCurrentMouthPoint(this Editor ed)
        {
            return ed.RunLisp("(grread T)", RunLispFlag.AcedEvaluateLisp)
                ?.AsArray()
                .FirstOrDefault(tv => tv.TypeCode == 5009)
                .Value as Point3d?;
        }











        #region 执行lisp

        [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "acedInvoke")]
        private static extern int AcedInvoke(IntPtr args, out IntPtr result);

        // 高版本此接口不能使用lisp(command "xx"),但是可以直接在自动运行接口上
        [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "?acedEvaluateLisp@@YAHPEB_WAEAPEAUresbuf@@@Z")]
        [System.Security.SuppressUnmanagedCodeSecurity] // 初始化默认值
        private static extern int AcedEvaluateLisp(string lispLine, out IntPtr result);

        [DllImport("accore.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl,
            EntryPoint = "ads_queueexpr")]
        private static extern int Ads_queueexpr(string strExpr);

        /// <summary>
        /// 执行lisp的方式枚举
        /// </summary>
        [Flags]
        public enum RunLispFlag : byte
        {
            /// <summary>
            /// AdsQueueexpr
            /// </summary>
            AdsQueueexpr = 1,

            /// <summary>
            /// AcedEvaluateLisp
            /// </summary>
            AcedEvaluateLisp = 2,

            /// <summary>
            /// SendStringToExecute
            /// </summary>
            SendStringToExecute = 4,
        }

        /*
         * 测试命令:
         *   [CommandMethod(nameof(CmdTest_RunLisp))]
         *   public static void CmdTest_RunLisp()
         *   {
         *       var res = RunLisp("(setq abc 10)");
         *   }
         * 调用方式:
         *    (command "CmdTest_RunLisp1")
         * bug说明:
         *    AcedEvaluateLisp 接口
         *    在高版本调用时候没有运行成功,使得 !abc 没有值
         *    在cad08成功,此bug与CommandFlags无关
         * 解决方案:
         *   0x01 用异步接口,但是这样是显式调用了:
         *        (setq thisdrawing (vla-get-activedocument (vlax-get-acad-object)))(vla-SendCommand thisdrawing "CmdTest_RunLisp1 ")
         *   0x02 使用 Ads_queueexpr 接口
         */
        /// <summary>
        /// 发送lisp语句字符串到cad执行
        /// </summary>
        /// <param name="ed">编辑器对象</param>
        /// <param name="lispCode">lisp语句</param>
        /// <param name="flag">运行方式</param>
        /// <returns>缓冲结果,返回值</returns>
        public static ResultBuffer RunLisp(this Editor ed, string lispCode,
            RunLispFlag flag = RunLispFlag.AdsQueueexpr)
        {
            if ((flag & RunLispFlag.AdsQueueexpr) == RunLispFlag.AdsQueueexpr)
            {
                // 这个在08/12发送lisp不会出错,但是发送bo命令出错了.
                // 0x01 设置RunLispFlag特性为RunLispFlag.AcedEvaluateLisp即可同步执行
                // 0x02 自执行发送lisp都是异步,用来发送 含有(command)的lisp的
                _ = Ads_queueexpr(lispCode + "\n");
            }

            if ((flag & RunLispFlag.AcedEvaluateLisp) == RunLispFlag.AcedEvaluateLisp)
            {
                _ = AcedEvaluateLisp(lispCode, out var rb);
                if (rb != IntPtr.Zero)
                    return (ResultBuffer)DisposableWrapper.Create(typeof(ResultBuffer), rb, true);
            }

            if ((flag & RunLispFlag.SendStringToExecute) == RunLispFlag.SendStringToExecute)
            {
                var dm = Application.DocumentManager;
                var doc = dm.MdiActiveDocument;
                doc?.SendStringToExecute(lispCode + "\n", false, false, false);
            }

            return null;
        }

        #endregion




        #region  实体相关操作


        /// <summary>
        /// 选择一个实体!
        /// </summary>
        /// <param name="ed">Editor</param>
        /// <param name="message">提示信息</param>
        /// <param name="type">类型</param>
        /// <returns>实体Id</returns>
        public static ObjectId GetEntity_(this Editor ed, string message, Type type = null)
        {
            if (ed is null) return ObjectId.Null;
            var option = new PromptEntityOptions(message);
            if (type != null)
            {
                option.SetRejectMessage(message);
                option.AddAllowedClass(type, true);
            }
            return ed.GetEntity(option).ObjectId;
        }




        /// <summary>
        /// GetSelection
        /// </summary>
        /// <param name="ed">editor</param>
        /// <param name="message">提示信息</param>
        /// <returns>实体id列表</returns>
        public static List<ObjectId> GetSelection_(this Editor ed, string message)
        {
            if (ed is null) return new List<ObjectId>();
            var opotion = new PromptSelectionOptions();
            opotion.MessageForAdding = message;
            opotion.RejectObjectsOnLockedLayers = false;

            var value = ed.GetSelection(opotion).Value;
            if (value is null) return new List<ObjectId>();
            return value.GetObjectIds().ToList();
        }
        /// <summary>
        /// 选择一个点
        /// </summary>
        /// <returns>3d点</returns>
        public static Point3d GetPoint(this Editor ed)
        {
            //Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            //定义一个用户交互类
            var opt = new PromptPointOptions("\n 选择一个点!");
            //允许None
            opt.AllowNone = true;
            var ppr = ed.GetPoint(opt);

            Point3d point = new Point3d();
            if (ppr.Status == PromptStatus.None) return point;
            if (ppr.Status == PromptStatus.Cancel) return point;
            if (ppr.Status == PromptStatus.OK)
            {
                point = ppr.Value;
            }
            return point;
        }




        /// <summary>
        /// 选择所有线 - Line 过滤器
        /// </summary>
        /// <param name="ed"></param>
        /// <returns></returns>
        public static List<Line> SelectAllLines(this Editor ed)
        {
            var filter = new SelectionFilter(new[]
            {
            new TypedValue((int)DxfCode.Start, "LINE")
        });
            PromptSelectionOptions pso = new PromptSelectionOptions
            {
                MessageForAdding = "\n选择所有线（直线）：",
                AllowDuplicates = false
            };
            var selection = ed.GetSelection(pso);
            if (selection.Status != PromptStatus.OK) return new List<Line>();

            using (var tr = ed.Document.TransactionManager.StartTransaction())
            {
                return selection.Value.GetObjectIds()
                    .Select(id => tr.GetObject(id, OpenMode.ForRead) as Line)
                    .Where(l => l != null)
                    .ToList();
            }
        }




        /// <summary>
        /// 选择一个点
        /// </summary>
        /// <returns></returns>
        public static Point3d GetPoint3d(this Editor ed, string prompt)
        {
            //定义一个用户交互类
            var opt = new PromptPointOptions($"\n {prompt}");
            //允许None
            opt.AllowNone = true;
            var ppr = ed.GetPoint(opt);

            Point3d point = new Point3d();
            if (ppr.Status == PromptStatus.None) return point;
            if (ppr.Status == PromptStatus.Cancel) return point;
            if (ppr.Status == PromptStatus.OK)
            {
                point = ppr.Value;
            }
            return point;
        }
        /// <summary>
        /// 选择一个点
        /// </summary>
        /// <returns></returns>
        public static Point3d GetPoint2(this Editor ed, string prompt)
        {
            //定义一个用户交互类
            var opt = new PromptPointOptions(prompt);
            //允许None
            opt.AllowNone = true;
            var ppr = ed.GetPoint(opt);

            Point3d point = new Point3d();
            if (ppr.Status == PromptStatus.None) return point;
            if (ppr.Status == PromptStatus.Cancel) return point;
            if (ppr.Status == PromptStatus.OK)
            {
                point = ppr.Value;
            }
            return point;
        }

        ///// <summary>
        ///// 选择实体（只选择线和多段线）过滤图层
        ///// </summary>
        ///// <param name="ed">AutoCAD编辑器对象</param>
        ///// <param name="message">提示信息</param>
        ///// <returns>用户选择集</returns>
        //public static ObjectId[] GetSelectionLineAndPolyLine(this Editor ed, string message, string layerName = "")
        //{
        //    var selectionOptions = new PromptSelectionOptions();
        //    var filterList = new TypedValue[]
        //    {
        //        // 只接受线和多段线
        //        new TypedValue((int)DxfCode.Operator, "<AND"),
        //        new TypedValue((int)DxfCode.Operator, "<OR"),
        //        new TypedValue((int)DxfCode.Start, "LINE"),
        //        new TypedValue((int)DxfCode.Start, "LWPOLYLINE"),
        //        new TypedValue((int)DxfCode.Operator, "OR>"),
        //        new TypedValue((int)DxfCode.Operator, "<OR"),
        //        new TypedValue((int)DxfCode.LayerName, layerName),  // 替换为您要过滤的图层名字
        //        new TypedValue((int)DxfCode.Operator, "OR>"),
        //        new TypedValue((int)DxfCode.Operator, "AND>"),
        //    };
        //    var selectionFilter = new SelectionFilter(filterList);
        //    selectionOptions.MessageForAdding = message;
        //    var selectionResult = ed.GetSelection(selectionOptions, selectionFilter);
        //                if (selectionResult.Status != PromptStatus.OK)
        //        return new ObjectId[0];

        //    // 返回选择集中的对象 IDs
        //    return selectionResult.Value.GetObjectIds();
        //}

        /// <summary>
        /// 选择实体（只选择线和多段线）并可选择过滤图层
        /// </summary>
        /// <param name="ed">AutoCAD编辑器对象</param>
        /// <param name="message">提示信息</param>
        /// <param name="layerName">图层名称（为空时不过滤图层）</param>
        /// <param name="allowMultiple">是否允许多选</param>
        /// <returns>用户选择的对象ID数组</returns>
        public static ObjectId[] GetSelectionLineAndPolyLine(this Editor ed, string message,
            string layerName = "", bool allowMultiple = true)
        {
            if (ed == null)
                throw new ArgumentNullException(nameof(ed));

            if (string.IsNullOrWhiteSpace(message))
                message = "请选择直线或多段线";

            try
            {
                var selectionOptions = new PromptSelectionOptions
                {
                    MessageForAdding = message,
                    AllowDuplicates = false,
                    SingleOnly = !allowMultiple,
                    RejectObjectsOnLockedLayers = true
                };

                // 构建选择过滤器
                SelectionFilter selectionFilter = CreateSelectionFilter(layerName);

                // 获取选择结果
                PromptSelectionResult selectionResult = ed.GetSelection(selectionOptions, selectionFilter);

                if (selectionResult.Status != PromptStatus.OK)
                    return CadArrayHelper.EmptyObjectIds;

                // 返回选择集中的对象IDs
                return selectionResult.Value.GetObjectIds();
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n选择操作出错: {ex.Message}");
                return CadArrayHelper.EmptyObjectIds;
            }
        }

        /// <summary>
        /// 创建选择过滤器
        /// </summary>
        private static SelectionFilter CreateSelectionFilter(string layerName)
        {
            var filterList = new List<TypedValue>();

            // 添加实体类型过滤（直线和多段线）
            filterList.Add(new TypedValue((int)DxfCode.Operator, "<AND"));
            filterList.Add(new TypedValue((int)DxfCode.Operator, "<OR"));
            filterList.Add(new TypedValue((int)DxfCode.Start, "LINE"));
            filterList.Add(new TypedValue((int)DxfCode.Start, "LWPOLYLINE"));
            filterList.Add(new TypedValue((int)DxfCode.Start, "POLYLINE")); // 添加旧式多段线支持
            filterList.Add(new TypedValue((int)DxfCode.Operator, "OR>"));

            // 如果指定了图层名称，添加图层过滤
            if (!string.IsNullOrWhiteSpace(layerName))
            {
                filterList.Add(new TypedValue((int)DxfCode.Operator, "<AND"));
                filterList.Add(new TypedValue((int)DxfCode.LayerName, layerName.Trim()));
                filterList.Add(new TypedValue((int)DxfCode.Operator, "AND>"));
            }

            filterList.Add(new TypedValue((int)DxfCode.Operator, "AND>"));

            return new SelectionFilter(filterList.ToArray());
        }

        /// <summary>
        /// 选择实体（只选择线和多段线）并支持多个图层过滤
        /// </summary>
        /// <param name="ed">AutoCAD编辑器对象</param>
        /// <param name="message">提示信息</param>
        /// <param name="layerNames">图层名称数组（为空时不过滤图层）</param>
        /// <param name="allowMultiple">是否允许多选</param>
        /// <returns>用户选择的对象ID数组</returns>
        public static ObjectId[] GetSelectionLineAndPolyLine(this Editor ed, string message,
            string[] layerNames, bool allowMultiple = true)
        {
            if (ed == null)
                throw new ArgumentNullException(nameof(ed));

            if (string.IsNullOrWhiteSpace(message))
                message = "请选择直线或多段线";

            if (layerNames == null || layerNames.Length == 0)
                return ed.GetSelectionLineAndPolyLine(message, "", allowMultiple);

            try
            {
                var selectionOptions = new PromptSelectionOptions
                {
                    MessageForAdding = message,
                    AllowDuplicates = false,
                    SingleOnly = !allowMultiple,
                    RejectObjectsOnLockedLayers = true
                };

                // 构建选择过滤器（支持多个图层）
                SelectionFilter selectionFilter = CreateMultiLayerSelectionFilter(layerNames);

                PromptSelectionResult selectionResult = ed.GetSelection(selectionOptions, selectionFilter);

                if (selectionResult.Status != PromptStatus.OK)
                    return CadArrayHelper.Empty<ObjectId>();

                return selectionResult.Value.GetObjectIds();
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n选择操作出错: {ex.Message}");
                return CadArrayHelper.Empty<ObjectId>();
            }
        }

        /// <summary>
        /// 创建多图层选择过滤器
        /// </summary>
        private static SelectionFilter CreateMultiLayerSelectionFilter(string[] layerNames)
        {
            var filterList = new List<TypedValue>();

            // 添加实体类型过滤
            filterList.Add(new TypedValue((int)DxfCode.Operator, "<AND"));
            filterList.Add(new TypedValue((int)DxfCode.Operator, "<OR"));
            filterList.Add(new TypedValue((int)DxfCode.Start, "LINE"));
            filterList.Add(new TypedValue((int)DxfCode.Start, "LWPOLYLINE"));
            filterList.Add(new TypedValue((int)DxfCode.Start, "POLYLINE"));
            filterList.Add(new TypedValue((int)DxfCode.Operator, "OR>"));

            // 添加多图层过滤
            if (layerNames != null && layerNames.Length > 0)
            {
                filterList.Add(new TypedValue((int)DxfCode.Operator, "<OR"));

                foreach (string layerName in layerNames.Where(ln => !string.IsNullOrWhiteSpace(ln)))
                {
                    filterList.Add(new TypedValue((int)DxfCode.LayerName, layerName.Trim()));
                }

                filterList.Add(new TypedValue((int)DxfCode.Operator, "OR>"));
            }

            filterList.Add(new TypedValue((int)DxfCode.Operator, "AND>"));

            return new SelectionFilter(filterList.ToArray());
        }

        /// <summary>
        /// 选择实体并返回实体对象列表
        /// </summary>
        /// <param name="ed">AutoCAD编辑器对象</param>
        /// <param name="message">提示信息</param>
        /// <param name="layerName">图层名称</param>
        /// <param name="transaction">事务对象</param>
        /// <returns>实体对象列表</returns>
        public static List<Entity> GetSelectionLineAndPolyLineEntities(this Editor ed, string message,
            string layerName, Transaction transaction)
        {
            if (transaction == null)
                throw new ArgumentNullException(nameof(transaction));

            ObjectId[] objectIds = ed.GetSelectionLineAndPolyLine(message, layerName);

            if (objectIds.Length == 0)
                return new List<Entity>();

            var entities = new List<Entity>();
            foreach (ObjectId objectId in objectIds)
            {
                try
                {
                    Entity entity = transaction.GetObject(objectId, OpenMode.ForRead) as Entity;
                    if (entity != null)
                    {
                        entities.Add(entity);
                    }
                }
                catch
                {
                    // 忽略无法获取的实体
                }
            }

            return entities;
        }

        /// <summary>
        /// 选择单个实体
        /// </summary>
        /// <param name="ed">AutoCAD编辑器对象</param>
        /// <param name="message">提示信息</param>
        /// <param name="layerName">图层名称</param>
        /// <returns>选择的实体ObjectId，如果取消选择返回ObjectId.Null</returns>
        public static ObjectId GetSingleSelectionLineOrPolyLine(this Editor ed, string message, string layerName = "")
        {
            ObjectId[] objectIds = ed.GetSelectionLineAndPolyLine(message, layerName, false);

            if (objectIds.Length == 0)
                return ObjectId.Null;

            return objectIds[0];
        }






















        /// <summary>
        /// 获取圆、圆弧
        /// </summary>
        /// <param name="doc">当前文档</param>
        /// <returns></returns>
        public static ObjectId[] SelectAllCircleArcs(this Document doc)
        {
            Editor ed = doc.Editor;

            // 创建一个选择过滤器来选择圆和圆弧
            TypedValue[] filterList = new TypedValue[]
            {
            new TypedValue((int)DxfCode.Start, "CIRCLE,ARC")
            };
            SelectionFilter filter = new SelectionFilter(filterList);

            // 提示用户选择圆和圆弧
            PromptSelectionResult selectionResult = ed.GetSelection(filter);

            if (selectionResult.Status != PromptStatus.OK)
                return new ObjectId[0];

            // 返回选择集中的对象 IDs
            return selectionResult.Value.GetObjectIds();
        }
        /// <summary>
        /// 获取圆、圆弧中心、半径
        /// </summary>
        /// <param name="objectIds"></param>
        /// <returns>中心、半径</returns>
        public static Dictionary<Point3d, double> GetCircleArcCenterRadius(this Document doc, ObjectId[] objectIds)
        {
            Dictionary<Point3d, double> centerRadiusDict = new Dictionary<Point3d, double>();

            Database db = doc.Database;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                foreach (ObjectId objectId in objectIds)
                {
                    Entity entity = tr.GetObject(objectId, OpenMode.ForRead) as Entity;
                    if (entity != null)
                    {
                        if (entity is Circle circle)
                        {
                            Point3d center = circle.Center;
                            double radius = circle.Radius;

                            centerRadiusDict.Add(center, radius);
                        }
                        else if (entity is Arc arc)
                        {
                            Point3d center = arc.Center;
                            double radius = arc.Radius;

                            centerRadiusDict.Add(center, radius);
                        }
                    }
                }

                tr.Commit();
            }

            return centerRadiusDict;
        }









        /// <summary>
        /// 获取圆、圆弧中心点和半径
        /// </summary>
        /// <param name="doc">文档对象</param>
        /// <param name="objectIds">对象ID数组</param>
        /// <param name="trans">事务对象</param>
        /// <param name="tolerance">点比较容差（避免重复中心点）</param>
        /// <returns>中心点与半径的字典</returns>
        public static Dictionary<Point3d, double> GetCircleArcCenterRadius(this Document doc,
            ObjectId[] objectIds, Transaction trans, double tolerance = 0.001)
        {
            if (doc == null)
                throw new ArgumentNullException(nameof(doc));

            if (objectIds == null)
                throw new ArgumentNullException(nameof(objectIds));

            if (trans == null)
                throw new ArgumentNullException(nameof(trans));

            // 使用比较器来处理点的近似相等
            var pointComparer = new Point3dComparer(tolerance);
            Dictionary<Point3d, double> centerRadiusDict = new Dictionary<Point3d, double>(pointComparer);

            foreach (ObjectId objectId in objectIds)
            {
                try
                {
                    if (objectId.IsNull || objectId.IsErased || !objectId.IsValid)
                        continue;

                    Entity entity = trans.GetObject(objectId, OpenMode.ForRead) as Entity;
                    if (entity == null)
                        continue;

                    ProcessEntity(entity, centerRadiusDict, pointComparer);
                }
                catch (System.Exception ex)
                {
                    // 记录错误但继续处理其他实体
                    doc.Editor.WriteMessage($"处理对象 {objectId} 时出错: {ex.Message}");
                }
            }

            return centerRadiusDict;
        }

        /// <summary>
        /// 处理单个实体
        /// </summary>
        private static void ProcessEntity(Entity entity, Dictionary<Point3d, double> centerRadiusDict, Point3dComparer comparer)
        {
            switch (entity)
            {
                case Circle circle:
                    AddCenterRadius(circle.Center, circle.Radius, centerRadiusDict, comparer);
                    break;

                case Arc arc:
                    AddCenterRadius(arc.Center, arc.Radius, centerRadiusDict, comparer);
                    break;

                case Ellipse ellipse when ellipse.Closed:
                    // 椭圆可以近似处理（如果需要）
                    AddCenterRadius(ellipse.Center, (ellipse.MajorRadius + ellipse.MinorRadius) / 2,
                        centerRadiusDict, comparer);
                    break;

                    // 可以添加其他曲线类型的支持
            }
        }

        /// <summary>
        /// 添加中心点和半径到字典
        /// </summary>
        private static void AddCenterRadius(Point3d center, double radius,
            Dictionary<Point3d, double> centerRadiusDict, Point3dComparer comparer)
        {
            // 检查是否已存在近似相同的点
            Point3d existingKey = centerRadiusDict.Keys.FirstOrDefault(
                key => comparer.Equals(key, center));

            if (existingKey != default(Point3d))
            {
                // 如果已存在，可以选择更新或跳过
                // 这里选择保留较大的半径值
                if (radius > centerRadiusDict[existingKey])
                {
                    centerRadiusDict[existingKey] = radius;
                }
            }
            else
            {
                centerRadiusDict.Add(center, radius);
            }
        }

        /// <summary>
        /// 点比较器（处理浮点数精度问题）
        /// </summary>
        public class Point3dComparer : IEqualityComparer<Point3d>
        {
            private readonly double _tolerance;

            public Point3dComparer(double tolerance = 0.001)
            {
                _tolerance = tolerance > 0 ? tolerance : 0.001;
            }

            public bool Equals(Point3d p1, Point3d p2)
            {
                if (p1 == p2) return true;
                if (p1 == null || p2 == null) return false;

                return p1.DistanceTo(p2) < _tolerance;
            }

            public int GetHashCode(Point3d obj)
            {
                if (obj == null)
                    return 0;

                // 基于容差的哈希计算（兼容旧版本.NET）
                unchecked
                {
                    // 将坐标标准化到容差网格
                    double normalizedX = Math.Round(obj.X / _tolerance) * _tolerance;
                    double normalizedY = Math.Round(obj.Y / _tolerance) * _tolerance;
                    double normalizedZ = Math.Round(obj.Z / _tolerance) * _tolerance;

                    // 使用质数进行哈希计算
                    int hash = 17;
                    hash = hash * 23 + normalizedX.GetHashCode();
                    hash = hash * 23 + normalizedY.GetHashCode();
                    hash = hash * 23 + normalizedZ.GetHashCode();
                    return hash;
                }
            }
        }

        /// <summary>
        /// 扩展方法：获取选择集并处理
        /// </summary>
        public static Dictionary<Point3d, double> GetCircleArcCenterRadiusFromSelection(this Document doc,
            string promptMessage, double tolerance = 0.001)
        {
            Editor ed = doc.Editor;

            try
            {
                // 选择圆和圆弧
                PromptSelectionResult selectionResult = ed.GetSelection();
                if (selectionResult.Status != PromptStatus.OK)
                    return new Dictionary<Point3d, double>();

                using (Transaction trans = doc.TransactionManager.StartTransaction())
                {
                    ObjectId[] objectIds = selectionResult.Value.GetObjectIds();
                    Dictionary<Point3d, double> result = doc.GetCircleArcCenterRadius(objectIds, trans, tolerance);

                    trans.Commit();
                    return result;
                }
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n错误: {ex.Message}");
                return new Dictionary<Point3d, double>();
            }
        }















        /// <summary>
        /// 选取直线集合
        /// </summary>
        /// <param name="doc">当前文档</param>
        /// <returns>直线列表</returns>
        public static List<Line> SelectLines(this Document doc)
        {
            var ed = doc.Editor;
            var lineList = new List<Line>();
            var lineValue = new TypedValue((int)DxfCode.Start, "LINE");
            var lineFilter = new SelectionFilter(new TypedValue[] { lineValue });
            var linePsr = ed.GetSelection(lineFilter);
            if (linePsr.Status != PromptStatus.OK)
                return lineList;
            var lineSet = linePsr.Value;
            var lineObjectIds = lineSet.GetObjectIds();
            foreach (var lineObjectId in lineObjectIds)
            {
                var itemEntity = doc.Database.GetEntity(lineObjectId);
                lineList.Add((Line)itemEntity);
            }
            return lineList;
        }
        /// <summary>
        /// 获取直线Id
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static List<ObjectId> SelectLineIds(this Document doc)
        {
            var ed = doc.Editor;
            var lineIdList = new List<ObjectId>();
            var lineValue = new TypedValue((int)DxfCode.Start, "LINE");
            var lineFilter = new SelectionFilter(new TypedValue[] { lineValue });
            var linePsr = ed.GetSelection(lineFilter);
            if (linePsr.Status != PromptStatus.OK)
                return lineIdList;
            var lineSet = linePsr.Value;
            var lineObjectIds = lineSet.GetObjectIds();
            foreach (var lineObjectId in lineObjectIds)
            {
                lineIdList.Add(lineObjectId);
            }
            return lineIdList;
        }



        /// <summary>
        /// 获取指定图层上的多段线
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="trans"></param>
        /// <param name="layerName"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static List<ObjectId> GetPolylineBySelectAndLayerName(this Document doc, Transaction trans, string layerName)
        {

            var ed = doc.Editor;
            var value = new TypedValue((int)DxfCode.Start, "LWPOLYLINE");
            var values = new TypedValue[] { value };
            var filter = new SelectionFilter(values);
            PromptSelectionResult selectionResult = ed.GetSelection(filter);

            if (selectionResult.Status != PromptStatus.OK)
                throw new ArgumentNullException("Select is Null");

            SelectionSet selectionSet = selectionResult.Value;
            List<ObjectId> filteredEntities = new List<ObjectId>();

            foreach (SelectedObject selectedObject in selectionSet)
            {
                var objectId = selectedObject.ObjectId;
                Entity entity = trans.GetObject(objectId, OpenMode.ForRead) as Entity;
                if (entity == null)
                    continue;
                if (entity.Layer == layerName)
                    filteredEntities.Add(objectId);
            }
            return filteredEntities;
        }


        /// <summary>
        /// 选取圆集合
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static List<Circle> SelectCircles(this Document doc)
        {
            var ed = doc.Editor;
            var cirList = new List<Circle>();
            var cirValue = new TypedValue((int)DxfCode.Start, "Circle");
            var cirFilter = new SelectionFilter(new TypedValue[] { cirValue });
            var cirPsr = ed.GetSelection(cirFilter);
            if (cirPsr.Status != PromptStatus.OK)
                return cirList;
            var cirSet = cirPsr.Value;
            var cirObjectIds = cirSet.GetObjectIds();
            foreach (var lineObjectId in cirObjectIds)
            {
                var itemEntity = doc.Database.GetEntity(lineObjectId);
                cirList.Add((Circle)itemEntity);
            }
            return cirList;
        }








        #endregion


        #region 选择集

        /// <summary>
        /// 输入过滤类型,获得选择集
        /// </summary>
        /// <param name="type">过滤类型</param>
        /// <returns>选择集</returns>
        public static SelectionSet GetSelectionEx(TypedValue[] type = null)
        {
            SelectionSet selection = PickFirst();
            if (selection != null) return selection;
            //过滤器
            SelectionFilter filter = new SelectionFilter(type);
            PromptSelectionResult promptResult;
            if (type == null)
            {
                promptResult = Application.DocumentManager.MdiActiveDocument.Editor.GetSelection();
            }
            else
            {
                promptResult = Application.DocumentManager.MdiActiveDocument.Editor.GetSelection(filter);
            }
            if (promptResult.Status == PromptStatus.OK)
            {
                selection = promptResult.Value;
            }
            return selection;
        }
        /// <summary>
        /// 获取选择集
        /// </summary>
        /// <returns></returns>
        public static SelectionSet PickFirst()
        {
            SelectionSet selection = null;

            PromptSelectionResult promptResult = Application.DocumentManager.MdiActiveDocument.Editor.SelectImplied();
            if (promptResult.Status == PromptStatus.OK)
            {
                selection = promptResult.Value;
            }
            return selection;
        }
        /// <summary>
        /// 选择
        /// </summary>
        /// <param name="ed"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static List<ObjectId> SelectAll_(this Editor ed, SelectionFilter filter = default)
        {
            if (ed is null) return new List<ObjectId>();
            var value = ed.SelectAll(filter).Value;
            if (value is null) return new List<ObjectId>();
            return value.GetObjectIds().ToList();
        }
        #endregion

        #region 获取输入
        /// <summary>
        /// 获得用户输入(Double)
        /// </summary>
        /// <param name="message">提示信息</param>
        /// <param name="value">默认值</param>
        /// <returns>值</returns>
        public static double GetUserDouble(this string message, double defaultvalue = 0.0)
        {
            PromptDoubleOptions promptDouble = new PromptDoubleOptions(message);
            promptDouble.DefaultValue = defaultvalue;
            var promptResult = Application.DocumentManager.MdiActiveDocument.Editor.GetDouble(promptDouble);
            if (promptResult.Status == PromptStatus.OK)
            {
                return promptResult.Value;
            }
            return 0;
        }
        public static double GetUserDouble(this Editor ed ,  string message, double defaultvalue = 0.0)
        {
            PromptDoubleOptions promptDouble = new PromptDoubleOptions(message);
            promptDouble.DefaultValue = defaultvalue;
            var promptResult = ed.GetDouble(promptDouble);
            if (promptResult.Status == PromptStatus.OK)
            {
                return promptResult.Value;
            }
            return 0;
        }


        /// <summary>
        /// 获取用户是否删除源对象的选择
        /// </summary>
        /// <param name="ed">编辑器对象</param>
        /// <param name="defaultChoice">默认选择(false=不删除)</param>
        /// <returns>用户选择(true=删除，false=不删除)，如果取消则返回null</returns>
        public static bool GetEraseSourceChoice(this Editor ed, bool defaultChoice = false)
        {
            PromptKeywordOptions pko = new PromptKeywordOptions("\n删除源对象?[是(Y)/否(N)]");
            pko.Keywords.Add("是");
            pko.Keywords.Add("Y");
            pko.Keywords.Add("否");
            pko.Keywords.Add("N");
            pko.Keywords.Default = defaultChoice ? "是" : "否";
            pko.AllowNone = true;

            PromptResult pkr = ed.GetKeywords(pko);

            if (pkr.Status == PromptStatus.Cancel || pkr.Status == PromptStatus.Error)
            {
                return false;
            }

            return pkr.StringResult == "是" || pkr.StringResult == "Y";
        }
        /// <summary>
        /// 获得用户输入(是或否)
        /// </summary>
        /// <param name="ed"></param>
        /// <param name="prompt"></param>
        /// <param name="defaultChoice"></param>
        /// <returns></returns>
        public static bool? GetUserYesOrNo(this Editor ed, string prompt = "\n是或否?[是(Y)/否(N)]", bool defaultChoice = false)
        {
            PromptKeywordOptions pko = new PromptKeywordOptions(prompt);
            pko.Keywords.Add("是");
            pko.Keywords.Add("Y");
            pko.Keywords.Add("否");
            pko.Keywords.Add("N");
            pko.Keywords.Default = defaultChoice ? "是" : "否";
            pko.AllowNone = true;

            PromptResult pkr = ed.GetKeywords(pko);

            if (pkr.Status == PromptStatus.Cancel || pkr.Status == PromptStatus.Error)
            {
                return null;
            }

            return pkr.StringResult == "是" || pkr.StringResult == "Y";
        }

        /// <summary>
        /// 获得用户输入(String
        /// </summary>
        /// <param name="message"></param>
        /// <returns>用户输入</returns>
        public static string GetUserMessage(this string message)
        {
            PromptStringOptions promptStr = new PromptStringOptions(message);

            var promptResult = Application.DocumentManager.MdiActiveDocument.Editor.GetString(promptStr);
            if (promptResult.Status == PromptStatus.OK)
            {
                return promptResult.StringResult;
            }
            return null;
        }
        /// <summary>
        /// 获得用户输入(String
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static string GetUserStr(this string message)
        {
            PromptStringOptions promptStr = new PromptStringOptions(message);

            var promptResult = Application.DocumentManager.MdiActiveDocument.Editor.GetString(promptStr);
            if (promptResult.Status == PromptStatus.OK)
            {
                return promptResult.StringResult;
            }
            return null;
        }
        /// <summary>
        /// 获得用户输入(Point3d
        /// </summary>
        /// <param name="message">提示信息</param> 
        /// <returns>点</returns>
        public static Point3d? GetPoint(this string message)
        {
            PromptPointOptions promptPoint = new PromptPointOptions(message);
            var promptResult = Application.DocumentManager.MdiActiveDocument.Editor.GetPoint(promptPoint);
            if (promptResult.Status == PromptStatus.OK)
            {
                return promptResult.Value;
            }
            return null;
        }
        #endregion


        /// <summary>
        /// 选择点
        /// </summary>
        /// <param name="ed"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static Point3d GetPoint_(this Editor ed, string message)
        {
            if (ed is null) return Point3d.Origin;
            var opotion = new PromptPointOptions(message);
            return ed.GetPoint(opotion).Value;
        }

        #region  获取弧度



        /// <summary>
        /// 获取用户输入的角度值
        /// </summary>
        /// <param name="promptMessage">提示信息</param>
        /// <param name="defaultValue">默认角度值（弧度）</param>
        /// <param name="useDegrees">是否使用角度制（默认true，false表示弧度制）</param>
        /// <param name="allowNone">是否允许不输入（按Enter使用默认值）</param>
        /// <returns>角度值（弧度），如果取消输入返回null</returns>
        public static double? GetAngleFromUser(
            this Editor ed,
            string promptMessage = "\n请输入角度:",
            double? defaultValue = null,
            bool useDegrees = true,
            bool allowNone = true)
        {

            try
            {
                PromptDoubleOptions pdo = new PromptDoubleOptions(promptMessage);

                // 设置默认值
                if (defaultValue.HasValue)
                {
                    double displayValue = useDegrees ? defaultValue.Value * (180.0 / Math.PI) : defaultValue.Value;
                    pdo.DefaultValue = displayValue;
                    pdo.UseDefaultValue = true;
                }

                pdo.AllowNone = allowNone;

                // 设置单位
                if (useDegrees)
                {
                    pdo.AppendKeywordsToMessage = true;
                    pdo.Keywords.Add("弧度");
                    pdo.Keywords.Add("度");
                    pdo.Keywords.Default = "度";
                }

                PromptDoubleResult pdr = ed.GetDouble(pdo);

                if (pdr.Status == PromptStatus.OK)
                {
                    double inputValue = pdr.Value;
                    return useDegrees ? inputValue * (Math.PI / 180.0) : inputValue;
                }
                else if (pdr.Status == PromptStatus.Keyword)
                {
                    // 处理单位切换
                    if (pdr.StringResult == "弧度")
                    {
                        return GetAngleFromUser(ed , promptMessage, defaultValue, false, allowNone);
                    }
                    else if (pdr.StringResult == "度")
                    {
                        return GetAngleFromUser(ed , promptMessage, defaultValue, true, allowNone);
                    }
                }
                else if (pdr.Status == PromptStatus.None && allowNone && defaultValue.HasValue)
                {
                    return defaultValue.Value;
                }

                return null; // 用户取消输入
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n输入错误: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 获取用户输入的角度值（带范围验证）
        /// </summary>
        /// <param name="promptMessage">提示信息</param>
        /// <param name="minValue">最小值（弧度）</param>
        /// <param name="maxValue">最大值（弧度）</param>
        /// <param name="defaultValue">默认角度值（弧度）</param>
        /// <param name="useDegrees">是否使用角度制</param>
        /// <returns>角度值（弧度），如果取消输入返回null</returns>
        public static double? GetAngleInRange(
            this Editor ed , 
            string promptMessage = "\n请输入角度:",
            double minValue = 0,
            double maxValue = 2 * Math.PI,
            double? defaultValue = null,
            bool useDegrees = true)
        {
            while (true)
            {
                double? angle = GetAngleFromUser(ed , promptMessage, defaultValue, useDegrees, defaultValue.HasValue);

                if (!angle.HasValue)
                    return null;

                if (angle >= minValue && angle <= maxValue)
                    return angle;

                // 显示范围错误信息
                string rangeMsg = useDegrees
                    ? $"角度必须在 {minValue * (180.0 / Math.PI):F1} 到 {maxValue * (180.0 / Math.PI):F1} 度之间"
                    : $"角度必须在 {minValue:F2} 到 {maxValue:F2} 弧度之间";

                ed.WriteMessage($"\n错误: {rangeMsg}");
            }
        }

        /// <summary>
        /// 通过两点获取角度
        /// </summary>
        /// <param name="basePoint">基点</param>
        /// <param name="promptMessage">提示信息</param>
        /// <returns>角度值（弧度），如果取消输入返回null</returns>
        public static double? GetAngleByTwoPoints(
            Point3d basePoint,
            string promptMessage = "\n指定角度方向:")
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            try
            {
                PromptPointOptions ppo = new PromptPointOptions(promptMessage);
                ppo.BasePoint = basePoint;
                ppo.UseBasePoint = true;
                ppo.UseDashedLine = true;

                PromptPointResult ppr = ed.GetPoint(ppo);

                if (ppr.Status == PromptStatus.OK)
                {
                    // 将3D向量转换为2D向量（忽略Z坐标）
                    Vector2d vector = new Vector2d(ppr.Value.X - basePoint.X, ppr.Value.Y - basePoint.Y);
                    return vector.Angle; // Vector2d 有 Angle 属性
                }

                return null;
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\n输入错误: {ex.Message}");
                return null;
            }
        }

        #endregion




        #region 过滤实体








        /*
        *
        *
        *# AutoCAD选择过滤器(DXF码)常用类型表格

            ## 常用实体类型过滤器

            | 实体类型 | DXF码 | 示例代码 |
            |---------|-------|----------|
            | 直线 | "LINE" | `new TypedValue((int)DxfCode.Start, "LINE")` |
            | 圆 | "CIRCLE" | `new TypedValue((int)DxfCode.Start, "CIRCLE")` |
            | 圆弧 | "ARC" | `new TypedValue((int)DxfCode.Start, "ARC")` |
            | 多段线 | "LWPOLYLINE" | `new TypedValue((int)DxfCode.Start, "LWPOLYLINE")` |
            | 多段线(旧版) | "POLYLINE" | `new TypedValue((int)DxfCode.Start, "POLYLINE")` |
            | 文字 | "TEXT" | `new TypedValue((int)DxfCode.Start, "TEXT")` |
            | 多行文字 | "MTEXT" | `new TypedValue((int)DxfCode.Start, "MTEXT")` |
            | 块参照 | "INSERT" | `new TypedValue((int)DxfCode.Start, "INSERT")` |
            | 尺寸标注 | "DIMENSION" | `new TypedValue((int)DxfCode.Start, "DIMENSION")` |
            | 填充 | "HATCH" | `new TypedValue((int)DxfCode.Start, "HATCH")` |
            | 样条曲线 | "SPLINE" | `new TypedValue((int)DxfCode.Start, "SPLINE")` |
            | 椭圆 | "ELLIPSE" | `new TypedValue((int)DxfCode.Start, "ELLIPSE")` |
            | 点 | "POINT" | `new TypedValue((int)DxfCode.Start, "POINT")` |
            | 所有实体 | "*" | `new TypedValue((int)DxfCode.Start, "*")` |

            ## 常用属性过滤器

            | 属性类型 | DXF码 | 示例代码 | 说明 |
            |---------|-------|----------|------|
            | 图层 | 8 | `new TypedValue(8, "图层名")` | 按图层过滤 |
            | 颜色 | 62 | `new TypedValue(62, 1)` | 按颜色索引过滤 |
            | 线型 | 6 | `new TypedValue(6, "线型名")` | 按线型过滤 |
            | 线宽 | 370 | `new TypedValue(370, 25)` | 按线宽过滤 |
            | 块名 | 2 | `new TypedValue(2, "块名")` | 按块名过滤 |
            | 文字内容 | 1 | `new TypedValue(1, "文字内容")` | 按文字内容过滤 |
            | 半径 | 40 | `new TypedValue(40, 10.0)` | 按半径过滤(圆) |
            | 标高 | 38 | `new TypedValue(38, 100.0)` | 按标高过滤 |

            ## 逻辑操作符

            | 操作符 | DXF码 | 示例代码 | 说明 |
            |--------|-------|----------|------|
            | 开始或 | -4 | `new TypedValue(-4, "<or")` | 开始"或"逻辑组 |
            | 结束或 | -4 | `new TypedValue(-4, "or>")` | 结束"或"逻辑组 |
            | 开始与 | -4 | `new TypedValue(-4, "<and")` | 开始"与"逻辑组 |
            | 结束与 | -4 | `new TypedValue(-4, "and>")` | 结束"与"逻辑组 |
            | 开始非 | -4 | `new TypedValue(-4, "<not")` | 开始"非"逻辑组 |
            | 结束非 | -4 | `new TypedValue(-4, "not>")` | 结束"非"逻辑组 |

            ## 常用组合过滤器示例

            ```csharp
            // 1. 选择特定图层的直线
            var filter1 = new SelectionFilter(new[]
            {
                new TypedValue((int)DxfCode.Start, "LINE"),
                new TypedValue(8, "墙线层") // 图层名
            });

            // 2. 选择红色或蓝色的圆
            var filter2 = new SelectionFilter(new[]
            {
                new TypedValue((int)DxfCode.Start, "CIRCLE"),
                new TypedValue(-4, "<or"),
                new TypedValue(62, 1),     // 红色
                new TypedValue(62, 5),     // 蓝色
                new TypedValue(-4, "or>")
            });

            // 3. 选择特定图层的所有实体
            var filter3 = new SelectionFilter(new[]
            {
                new TypedValue((int)DxfCode.Start, "*"),     // 所有实体
                new TypedValue(8, "标注层")                  // 图层名
            });

            // 4. 选择非锁定图层上的多段线
            var filter4 = new SelectionFilter(new[]
            {
                new TypedValue((int)DxfCode.Start, "LWPOLYLINE"),
                new TypedValue(-4, "<not"),
                new TypedValue(8, "锁定层"), // 排除的图层
                new TypedValue(-4, "not>")
            });

            // 5. 选择半径大于5的圆
            var filter5 = new SelectionFilter(new[]
            {
                new TypedValue((int)DxfCode.Start, "CIRCLE"),
                new TypedValue(-4, ">"),
                new TypedValue(40, 5.0),   // 半径 > 5
                new TypedValue(-4, ">")
            });
            ```

            ## 比较操作符

            | 操作符 | DXF码 | 说明 | 示例 |
            |--------|-------|------|------|
            | 等于 | 无 | 默认比较 | `new TypedValue(8, "图层名")` |
            | 不等于 | -4 | `"<>"` | `new TypedValue(-4, "<>"), new TypedValue(8, "排除层")` |
            | 大于 | -4 | `">"` | `new TypedValue(-4, ">"), new TypedValue(40, 5.0)` |
            | 小于 | -4 | `"<"` | `new TypedValue(-4, "<"), new TypedValue(40, 10.0)` |
            | 大于等于 | -4 | `">="` | `new TypedValue(-4, ">="), new TypedValue(40, 5.0)` |
            | 小于等于 | -4 | `"<="` | `new TypedValue(-4, "<="), new TypedValue(40, 10.0)` |

            这个表格涵盖了AutoCAD选择过滤器中最常用的DXF码和实体类型，您可以根据需要组合使用这些过滤器来创建精确的选择条件。
        *
         */











        /// <summary>
        /// 通过过滤器获取实体
        /// </summary>
        /// <param name="ed">editor</param>
        /// <param name="type">过滤类型</param>
        /// <returns>实体</returns>
        public static SelectionSet GetSelectionEntity(this Editor ed, TypedValue[] type = null)
        {
            SelectionSet selection = ed.SelectSet();
            if (selection != null) return selection;
            //过滤器
            SelectionFilter filter = new SelectionFilter(type);
            PromptSelectionResult promptResult;
            if (type == null)
            {
                promptResult = ed.GetSelection();
            }
            else
            {
                promptResult = ed.GetSelection(filter);
            }
            if (promptResult.Status == PromptStatus.OK)
            {
                selection = promptResult.Value;
            }
            return selection;
        }
        /// <summary>
        /// 通过过滤器获取实体
        /// </summary>
        /// <param name="ed"></param>
        /// <returns></returns>
        public static SelectionSet SelectSet(this Editor ed)
        {
            SelectionSet selection = null;

            PromptSelectionResult promptResult = ed.SelectImplied();
            if (promptResult.Status == PromptStatus.OK)
            {
                selection = promptResult.Value;
            }
            return selection;
        }

        #endregion


        #region 刷新视图
        /// <summary>
        /// 刷新当前文档视图
        /// </summary>
        /// <param name="document">要刷新的文档对象（如果为null则使用当前活动文档）</param>
        public static void RefreshView(this Document document)
        {
            try
            {
                // 如果未传入document参数，则使用当前活动文档
                Document doc = document ?? Application.DocumentManager.MdiActiveDocument;

                // 使用文档锁确保线程安全
                using (DocumentLock docLock = doc.LockDocument())
                {
                    // 获取编辑器对象
                    Editor ed = doc.Editor;

                    // 执行刷新操作
                    ed.Regen();
                    ed.UpdateScreen();

                    // 可选：添加提示信息（调试时可开启）
                    // ed.WriteMessage("\n视图已刷新");
                }
            }
            catch (System.Exception ex)
            {
                // 获取当前编辑器以显示错误信息
                Editor errorEd = Application.DocumentManager.MdiActiveDocument.Editor;
                errorEd.WriteMessage($"\n刷新视图错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 缩放至全部范围
        /// </summary>
        /// <param name="document">要操作的文档对象（如果为null则使用当前活动文档）</param>
        public static void ZoomExtents(this Document document)
        {
            try
            {
                Document doc = document ?? Application.DocumentManager.MdiActiveDocument;

                using (DocumentLock docLock = doc.LockDocument())
                {
                    Editor ed = doc.Editor;

                    // 执行缩放至全部范围
                    ed.Command("_.ZOOM", "_E");

                    // 刷新视图确保显示正确
                    RefreshView(doc);
                }
            }
            catch (System.Exception ex)
            {
                Editor errorEd = Application.DocumentManager.MdiActiveDocument.Editor;
                errorEd.WriteMessage($"\n缩放至全部范围错误: {ex.Message}");
            }
        }
        /*
         * 使用说明：
            基本刷新视图： 

            csharp
            // 刷新当前活动文档视图
            CadViewOperations.RefreshView();

            // 刷新指定文档视图
            Document someDoc = ...; // 获取某个文档对象
            CadViewOperations.RefreshView(someDoc);
            缩放至全部范围：

            csharp
            // 缩放当前活动文档
            CadViewOperations.ZoomExtents();

            // 缩放指定文档
            Document someDoc = ...; // 获取某个文档对象
            CadViewOperations.ZoomExtents(someDoc);
         */

        #endregion
    }
}
